﻿// Decompiled with JetBrains decompiler
// Type: UnityEngine.ComputeBuffer
// Assembly: UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E6AE6B5A-2752-4B07-9528-C8B77C62CE79
// Assembly location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll
// XML documentation location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.xml

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Bindings;
using UnityEngine.Scripting;

#nullable disable
namespace UnityEngine
{
  /// <summary>
  ///   <para>GPU data buffer, mostly for use with compute shaders.</para>
  /// </summary>
  [NativeHeader("Runtime/Shaders/GraphicsBuffer.h")]
  [UsedByNativeCode]
  [NativeClass("GraphicsBuffer")]
  [NativeHeader("Runtime/Export/Graphics/GraphicsBuffer.bindings.h")]
  public sealed class ComputeBuffer : IDisposable
  {
    internal IntPtr m_Ptr;
    private AtomicSafetyHandle m_Safety;

    ~ComputeBuffer() => this.Dispose(false);

    public void Dispose()
    {
      this.Dispose(true);
      GC.SuppressFinalize((object) this);
    }

    private void Dispose(bool disposing)
    {
      if (disposing)
      {
        ComputeBuffer.DestroyBuffer(this);
        this.RemoveBufferFromLeakDetector();
      }
      else if (this.m_Ptr != IntPtr.Zero && UnsafeUtility.GetLeakDetectionMode() == NativeLeakDetectionMode.Disabled)
        Debug.LogWarning((object) "GarbageCollector disposing of ComputeBuffer. Please use ComputeBuffer.Release() or .Dispose() to manually release the buffer. To see the stack trace where the leaked resource was allocated, set the UnsafeUtility LeakDetectionMode to EnabledWithStackTrace.");
      this.m_Ptr = IntPtr.Zero;
    }

    [FreeFunction("GraphicsBuffer_Bindings::InitComputeBuffer")]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern IntPtr InitBuffer(
      int count,
      int stride,
      ComputeBufferType type,
      ComputeBufferMode usage);

    [FreeFunction("GraphicsBuffer_Bindings::DestroyBuffer")]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern void DestroyBuffer(ComputeBuffer buf);

    /// <summary>
    ///   <para>Create a Compute Buffer.</para>
    /// </summary>
    /// <param name="count">Number of elements in the buffer.</param>
    /// <param name="stride">Size of one element in the buffer, in bytes. Must be a multiple of 4 and less than 2048, and match the size of the buffer type in the shader. See for cross-platform compatibility information.</param>
    /// <param name="type">Type of the buffer, default is ComputeBufferType.Default (structured buffer).</param>
    /// <param name="usage">Usage mode of the buffer, default is ComputeBufferModeImmutable.</param>
    public ComputeBuffer(int count, int stride)
      : this(count, stride, ComputeBufferType.Default, ComputeBufferMode.Immutable, 3)
    {
    }

    /// <summary>
    ///   <para>Create a Compute Buffer.</para>
    /// </summary>
    /// <param name="count">Number of elements in the buffer.</param>
    /// <param name="stride">Size of one element in the buffer, in bytes. Must be a multiple of 4 and less than 2048, and match the size of the buffer type in the shader. See for cross-platform compatibility information.</param>
    /// <param name="type">Type of the buffer, default is ComputeBufferType.Default (structured buffer).</param>
    /// <param name="usage">Usage mode of the buffer, default is ComputeBufferModeImmutable.</param>
    public ComputeBuffer(int count, int stride, ComputeBufferType type)
      : this(count, stride, type, ComputeBufferMode.Immutable, 3)
    {
    }

    /// <summary>
    ///   <para>Create a Compute Buffer.</para>
    /// </summary>
    /// <param name="count">Number of elements in the buffer.</param>
    /// <param name="stride">Size of one element in the buffer, in bytes. Must be a multiple of 4 and less than 2048, and match the size of the buffer type in the shader. See for cross-platform compatibility information.</param>
    /// <param name="type">Type of the buffer, default is ComputeBufferType.Default (structured buffer).</param>
    /// <param name="usage">Usage mode of the buffer, default is ComputeBufferModeImmutable.</param>
    public ComputeBuffer(int count, int stride, ComputeBufferType type, ComputeBufferMode usage)
      : this(count, stride, type, usage, 3)
    {
    }

    private ComputeBuffer(
      int count,
      int stride,
      ComputeBufferType type,
      ComputeBufferMode usage,
      int stackDepth)
    {
      if (count <= 0)
        throw new ArgumentException("Attempting to create a zero length compute buffer", nameof (count));
      if (stride <= 0)
        throw new ArgumentException("Attempting to create a compute buffer with a negative or null stride", nameof (stride));
      long num = (long) count * (long) stride;
      long graphicsBufferSize = SystemInfo.maxGraphicsBufferSize;
      if (num > graphicsBufferSize)
        throw new ArgumentException(string.Format("The total size of the compute buffer ({0} bytes) exceeds the maximum buffer size. Maximum supported buffer size: {1} bytes.", (object) num, (object) graphicsBufferSize));
      this.m_Ptr = ComputeBuffer.InitBuffer(count, stride, type, usage);
      this.AddBufferToLeakDetector();
    }

    /// <summary>
    ///   <para>Release a Compute Buffer.</para>
    /// </summary>
    public void Release() => this.Dispose();

    [FreeFunction("GraphicsBuffer_Bindings::IsValidBuffer")]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern bool IsValidBuffer(ComputeBuffer buf);

    /// <summary>
    ///   <para>Returns true if this compute buffer is valid and false otherwise.</para>
    /// </summary>
    public bool IsValid() => this.m_Ptr != IntPtr.Zero && ComputeBuffer.IsValidBuffer(this);

    /// <summary>
    ///   <para>Number of elements in the buffer (Read Only).</para>
    /// </summary>
    public extern int count { [MethodImpl(MethodImplOptions.InternalCall)] get; }

    /// <summary>
    ///   <para>Size of one element in the buffer in bytes (Read Only).</para>
    /// </summary>
    public extern int stride { [MethodImpl(MethodImplOptions.InternalCall)] get; }

    private extern ComputeBufferMode usage { [MethodImpl(MethodImplOptions.InternalCall)] get; }

    /// <summary>
    ///   <para>Set the buffer with values from an array.</para>
    /// </summary>
    /// <param name="data">Array of values to fill the buffer.</param>
    [SecuritySafeCritical]
    public void SetData(Array data)
    {
      if (data == null)
        throw new ArgumentNullException(nameof (data));
      if (!UnsafeUtility.IsArrayBlittable(data))
        throw new ArgumentException(string.Format("Array passed to ComputeBuffer.SetData(array) must be blittable.\n{0}", (object) UnsafeUtility.GetReasonForArrayNonBlittable(data)));
      this.InternalSetData(data, 0, 0, data.Length, UnsafeUtility.SizeOf(data.GetType().GetElementType()));
    }

    [SecuritySafeCritical]
    public void SetData<T>(List<T> data) where T : struct
    {
      if (data == null)
        throw new ArgumentNullException(nameof (data));
      if (!UnsafeUtility.IsGenericListBlittable<T>())
        throw new ArgumentException(string.Format("List<{0}> passed to ComputeBuffer.SetData(List<>) must be blittable.\n{1}", (object) typeof (T), (object) UnsafeUtility.GetReasonForGenericListNonBlittable<T>()));
      this.InternalSetData(NoAllocHelpers.ExtractArrayFromList((object) data), 0, 0, NoAllocHelpers.SafeLength<T>(data), Marshal.SizeOf(typeof (T)));
    }

    [SecuritySafeCritical]
    public unsafe void SetData<T>(NativeArray<T> data) where T : struct
    {
      this.InternalSetNativeData((IntPtr) data.GetUnsafeReadOnlyPtr<T>(), 0, 0, data.Length, UnsafeUtility.SizeOf<T>());
    }

    /// <summary>
    ///   <para>Partial copy of data values from an array into the buffer.</para>
    /// </summary>
    /// <param name="data">Array of values to fill the buffer.</param>
    /// <param name="managedBufferStartIndex">The first element index in data to copy to the compute buffer.</param>
    /// <param name="computeBufferStartIndex">The first element index in compute buffer to receive the data.</param>
    /// <param name="count">The number of elements to copy.</param>
    /// <param name="nativeBufferStartIndex"></param>
    [SecuritySafeCritical]
    public void SetData(
      Array data,
      int managedBufferStartIndex,
      int computeBufferStartIndex,
      int count)
    {
      if (data == null)
        throw new ArgumentNullException(nameof (data));
      if (!UnsafeUtility.IsArrayBlittable(data))
        throw new ArgumentException(string.Format("Array passed to ComputeBuffer.SetData(array) must be blittable.\n{0}", (object) UnsafeUtility.GetReasonForArrayNonBlittable(data)));
      if (managedBufferStartIndex < 0 || computeBufferStartIndex < 0 || count < 0 || managedBufferStartIndex + count > data.Length)
        throw new ArgumentOutOfRangeException(string.Format("Bad indices/count arguments (managedBufferStartIndex:{0} computeBufferStartIndex:{1} count:{2})", (object) managedBufferStartIndex, (object) computeBufferStartIndex, (object) count));
      this.InternalSetData(data, managedBufferStartIndex, computeBufferStartIndex, count, Marshal.SizeOf(data.GetType().GetElementType()));
    }

    [SecuritySafeCritical]
    public void SetData<T>(
      List<T> data,
      int managedBufferStartIndex,
      int computeBufferStartIndex,
      int count)
      where T : struct
    {
      if (data == null)
        throw new ArgumentNullException(nameof (data));
      if (!UnsafeUtility.IsGenericListBlittable<T>())
        throw new ArgumentException(string.Format("List<{0}> passed to ComputeBuffer.SetData(List<>) must be blittable.\n{1}", (object) typeof (T), (object) UnsafeUtility.GetReasonForGenericListNonBlittable<T>()));
      if (managedBufferStartIndex < 0 || computeBufferStartIndex < 0 || count < 0 || managedBufferStartIndex + count > data.Count)
        throw new ArgumentOutOfRangeException(string.Format("Bad indices/count arguments (managedBufferStartIndex:{0} computeBufferStartIndex:{1} count:{2})", (object) managedBufferStartIndex, (object) computeBufferStartIndex, (object) count));
      this.InternalSetData(NoAllocHelpers.ExtractArrayFromList((object) data), managedBufferStartIndex, computeBufferStartIndex, count, Marshal.SizeOf(typeof (T)));
    }

    [SecuritySafeCritical]
    public unsafe void SetData<T>(
      NativeArray<T> data,
      int nativeBufferStartIndex,
      int computeBufferStartIndex,
      int count)
      where T : struct
    {
      if (nativeBufferStartIndex < 0 || computeBufferStartIndex < 0 || count < 0 || nativeBufferStartIndex + count > data.Length)
        throw new ArgumentOutOfRangeException(string.Format("Bad indices/count arguments (nativeBufferStartIndex:{0} computeBufferStartIndex:{1} count:{2})", (object) nativeBufferStartIndex, (object) computeBufferStartIndex, (object) count));
      this.InternalSetNativeData((IntPtr) data.GetUnsafeReadOnlyPtr<T>(), nativeBufferStartIndex, computeBufferStartIndex, count, UnsafeUtility.SizeOf<T>());
    }

    [FreeFunction(Name = "GraphicsBuffer_Bindings::InternalSetNativeData", HasExplicitThis = true, ThrowsException = true)]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void InternalSetNativeData(
      IntPtr data,
      int nativeBufferStartIndex,
      int computeBufferStartIndex,
      int count,
      int elemSize);

    [FreeFunction(Name = "GraphicsBuffer_Bindings::InternalSetData", HasExplicitThis = true, ThrowsException = true)]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void InternalSetData(
      Array data,
      int managedBufferStartIndex,
      int computeBufferStartIndex,
      int count,
      int elemSize);

    /// <summary>
    ///   <para>Read data values from the buffer into an array. The array can only use &lt;a href="https:docs.microsoft.comen-usdotnetframeworkinteropblittable-and-non-blittable-types"&gt;blittable&lt;a&gt; types.</para>
    /// </summary>
    /// <param name="data">An array to receive the data.</param>
    [SecurityCritical]
    public void GetData(Array data)
    {
      if (data == null)
        throw new ArgumentNullException(nameof (data));
      if (!UnsafeUtility.IsArrayBlittable(data))
        throw new ArgumentException(string.Format("Array passed to ComputeBuffer.GetData(array) must be blittable.\n{0}", (object) UnsafeUtility.GetReasonForArrayNonBlittable(data)));
      this.InternalGetData(data, 0, 0, data.Length, Marshal.SizeOf(data.GetType().GetElementType()));
    }

    /// <summary>
    ///   <para>Partial read of data values from the buffer into an array.</para>
    /// </summary>
    /// <param name="data">An array to receive the data.</param>
    /// <param name="managedBufferStartIndex">The first element index in data where retrieved elements are copied.</param>
    /// <param name="computeBufferStartIndex">The first element index of the compute buffer from which elements are read.</param>
    /// <param name="count">The number of elements to retrieve.</param>
    [SecurityCritical]
    public void GetData(
      Array data,
      int managedBufferStartIndex,
      int computeBufferStartIndex,
      int count)
    {
      if (data == null)
        throw new ArgumentNullException(nameof (data));
      if (!UnsafeUtility.IsArrayBlittable(data))
        throw new ArgumentException(string.Format("Array passed to ComputeBuffer.GetData(array) must be blittable.\n{0}", (object) UnsafeUtility.GetReasonForArrayNonBlittable(data)));
      if (managedBufferStartIndex < 0 || computeBufferStartIndex < 0 || count < 0 || managedBufferStartIndex + count > data.Length)
        throw new ArgumentOutOfRangeException(string.Format("Bad indices/count argument (managedBufferStartIndex:{0} computeBufferStartIndex:{1} count:{2})", (object) managedBufferStartIndex, (object) computeBufferStartIndex, (object) count));
      this.InternalGetData(data, managedBufferStartIndex, computeBufferStartIndex, count, Marshal.SizeOf(data.GetType().GetElementType()));
    }

    [FreeFunction(Name = "GraphicsBuffer_Bindings::InternalGetData", HasExplicitThis = true, ThrowsException = true)]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void InternalGetData(
      Array data,
      int managedBufferStartIndex,
      int computeBufferStartIndex,
      int count,
      int elemSize);

    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern unsafe void* BeginBufferWrite(int offset = 0, int size = 0);

    public unsafe NativeArray<T> BeginWrite<T>(int computeBufferStartIndex, int count) where T : struct
    {
      if (!this.IsValid())
        throw new InvalidOperationException("BeginWrite requires a valid ComputeBuffer");
      if (this.usage != ComputeBufferMode.SubUpdates)
        throw new ArgumentException("ComputeBuffer must be created with usage mode ComputeBufferMode.SubUpdates to be able to be mapped with BeginWrite");
      int num = UnsafeUtility.SizeOf<T>();
      if (computeBufferStartIndex < 0 || count < 0 || (computeBufferStartIndex + count) * num > this.count * this.stride)
        throw new ArgumentOutOfRangeException(string.Format("Bad indices/count arguments (computeBufferStartIndex:{0} count:{1} elementSize:{2}, this.count:{3}, this.stride{4})", (object) computeBufferStartIndex, (object) count, (object) num, (object) this.count, (object) this.stride));
      NativeArray<T> nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<T>(this.BeginBufferWrite(computeBufferStartIndex * num, count * num), count, Allocator.Invalid);
      this.m_Safety = AtomicSafetyHandle.Create();
      AtomicSafetyHandle.SetAllowSecondaryVersionWriting(this.m_Safety, true);
      NativeArrayUnsafeUtility.SetAtomicSafetyHandle<T>(ref nativeArray, this.m_Safety);
      return nativeArray;
    }

    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void EndBufferWrite(int bytesWritten = 0);

    public void EndWrite<T>(int countWritten) where T : struct
    {
      try
      {
        AtomicSafetyHandle.CheckExistsAndThrow(in this.m_Safety);
        AtomicSafetyHandle.Release(this.m_Safety);
      }
      catch (Exception ex)
      {
        throw new InvalidOperationException("ComputeBuffer.EndWrite was called without matching ComputeBuffer.BeginWrite", ex);
      }
      if (countWritten < 0)
        throw new ArgumentOutOfRangeException(string.Format("Bad indices/count arguments (countWritten:{0})", (object) countWritten));
      int num = UnsafeUtility.SizeOf<T>();
      this.EndBufferWrite(countWritten * num);
    }

    /// <summary>
    ///   <para>The debug label for the compute buffer (setter only).</para>
    /// </summary>
    public string name
    {
      set => this.SetName(value);
    }

    [FreeFunction(Name = "GraphicsBuffer_Bindings::SetName", HasExplicitThis = true)]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void SetName(string name);

    /// <summary>
    ///   <para>Sets counter value of append/consume buffer.</para>
    /// </summary>
    /// <param name="counterValue">Value of the append/consume counter.</param>
    [MethodImpl(MethodImplOptions.InternalCall)]
    public extern void SetCounterValue(uint counterValue);

    /// <summary>
    ///   <para>Copy counter value of append/consume buffer into another buffer.</para>
    /// </summary>
    /// <param name="src">Append/consume buffer to copy the counter from.</param>
    /// <param name="dst">A buffer to copy the counter to.</param>
    /// <param name="dstOffsetBytes">Target byte offset in dst.</param>
    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern void CopyCount(ComputeBuffer src, ComputeBuffer dst, int dstOffsetBytes);

    /// <summary>
    ///   <para>Retrieve a native (underlying graphics API) pointer to the buffer.</para>
    /// </summary>
    /// <returns>
    ///   <para>Pointer to the underlying graphics API buffer.</para>
    /// </returns>
    [MethodImpl(MethodImplOptions.InternalCall)]
    public extern IntPtr GetNativeBufferPtr();

    internal void AddBufferToLeakDetector()
    {
      IntPtr ptr = this.m_Ptr;
      if (false)
        return;
      UnsafeUtility.LeakRecord(this.m_Ptr, LeakCategory.Persistent, 2);
    }

    internal void RemoveBufferFromLeakDetector()
    {
      IntPtr ptr = this.m_Ptr;
      if (false)
        return;
      UnsafeUtility.LeakErase(this.m_Ptr, LeakCategory.Persistent);
    }
  }
}
